use std::ops::{Add, Deref, DerefMut, Index, IndexMut, Neg, Sub};
use crate::egui::{Pos2, Rect};

pub fn test() {
    let n1 = Value::Num(3);
    let n2 = Value::Num(2);
    let v1 = Value::Var(Variable::new('a', None));
    let v2 = Value::Var(Variable::new('b', None));
    let m1 = Value::Mono(Monomial::new(vec![n1.clone(), v1.clone(), v2.clone()]));
    let m2 = Value::Mono(Monomial::new(vec![n1.clone(), v2.clone(), v1.clone()]));
    let m3 = Value::Mono(Monomial::new(vec![n2.clone(), v2.clone(), v1.clone()]));
    assert!(m1.same_after_moving(&m2));
    assert!(!m1.same_after_moving(&m3));
}

/// currently using arena to store propositions, kind of manual memory management.
/// could also be maps using keys to store reference
/// currently it is an arena which only grows
#[derive(Debug)]
pub struct PropSys {
    pub contents: Vec<Option<Proposition>>,
    frees: Vec<usize>,
}
impl PropSys {
    pub fn new() -> Self {
        Self { contents: Vec::new(), frees: Vec::new() }
    }
    pub fn add_prop(&mut self, content: PropContent, derived_from: Vec<usize>, pos: Pos2) -> usize {
        let proposition = Proposition::new(content, pos, derived_from);
        if let Some(index) = self.frees.pop() {
            self.contents[index] = Some(proposition);
            index
        } else {
            let index = self.contents.len();
            self.contents.push(Some(proposition));
            index
        }
    }
    pub fn create_eqv(&mut self, content: PropContent, from: usize, pos: Pos2) -> usize {
        let new = self.add_prop(content, vec![from], pos);
        self[new].infer_list.push(from);
        self[from].infer_list.push(new);
        self[from].derived_from.push(new);
        new
    }
    
    // returns the error information when removing failed
    pub fn try_remove_prop(&mut self, prop: usize) -> Result<(), &'static str> {
        let proposition = self.contents[prop].as_ref().ok_or("Proposition not found")?;
        if proposition.join_infer_list.len() > 0{
            Err("There are some other proposition depending on this one.")
        } else {
            self.contents[prop] = None;
            self.frees.push(prop);
            for i in 0..self.contents.len() {
                let others = if let Some(ref mut prop) = self.contents[i] {
                    prop
                } else {
                    continue;
                };
                others.infer_list.retain(|i| *i != prop);
                others.derived_from.retain(|i| *i != prop);
            }
            Ok(())
        }
    }
    pub fn get(&self, index: usize) -> Option<&Proposition> {
        self.contents[index].as_ref()
    }
    pub fn iter(&self) -> PropIter {
        PropIter { sys: self, next_i: 0 }
    }
}

impl Index<usize> for PropSys {
    type Output = Proposition;
    fn index(&self, index: usize) -> &Self::Output {
        self.contents[index].as_ref().unwrap()
    }
}

impl IndexMut<usize> for PropSys {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        self.contents[index].as_mut().unwrap()
    }
}

pub struct PropIter<'a> {
    sys: &'a PropSys,
    next_i: usize
}
impl<'a> Iterator for PropIter<'a> {
    type Item = &'a Proposition;
    fn next(&mut self) -> Option<Self::Item> {
        while self.next_i < self.sys.contents.len() {
            if let Some(ref prop) = self.sys.contents[self.next_i] {
                self.next_i += 1;
                return Some(prop)
            }
            self.next_i += 1;
        }
        None
    }
}


#[derive(Debug)]
pub struct Proposition {
    pub content: PropContent,
    pub infer_list: Vec<usize>,
    /// When the proposition is removed, this is used for deleting the pointer of it in those that infer it.
    pub derived_from: Vec<usize>,
    /// representing there is another proposition that is the union of this prosition and some other propositions
    pub join_infer_list: Vec<usize>,

    // for user interface
    pub rect: Rect,
}

impl Proposition {
    pub fn new(content: PropContent, pos: Pos2, derived_from: Vec<usize>) -> Self {
        Self { content, infer_list: Vec::new(), derived_from, join_infer_list: Vec::new(), rect: Rect::from_min_max(pos, pos) }
    }
}

#[derive(Debug)]
pub enum PropContent {
    Eq(Equation),
    // Union(Vec<usize>),
    None
}

#[derive(Debug, Clone)]
pub struct Equation {
    pub left: Value,
    pub right: Value,
}

impl Equation {
    pub fn new(left: Value, right: Value) -> Self {
        Self { left, right }
    }
    pub fn child(&self, index: usize) -> Option<&Value> {
        if index == 0 {
            Some(&self.left)
        } else if index == 1 {
            Some(&self.right)
        } else {
            None
        }
    }
    pub fn child_mut(&mut self, index: usize) -> Option<&mut Value> {
        if index == 0 {
            Some(&mut self.left)
        } else if index == 1 {
            Some(&mut self.right)
        } else {
            None
        }
    }
    pub fn get(&self, pointer: &[usize]) -> Option<&Value> {
        if pointer.len() == 0 {
            None
        } else {
            if pointer.len() == 1 {
                self.child(pointer[0])
            } else {
                self.child(pointer[0])?.get(&pointer[1..])
            }
        }
    }
    pub fn get_mut(&mut self, pointer: &[usize]) -> Option<&mut Value> {
        if pointer.len() == 0 {
            None
        } else {
            if pointer.len() == 1 {
                self.child_mut(pointer[0])
            } else {
                self.child_mut(pointer[0])?.get_mut(&pointer[1..])
            }
        }
    }
}

#[derive(Debug, Clone)]
pub enum Value {
    Var(Variable),
    Num(usize),
    Mono(Monomial),
    Poly(Polynomial),
    Signed(Signed),
}
impl Neg for &Value {
    type Output = Value;
    fn neg(self) -> Self::Output {
        Value::Signed(Signed::new(Sign::Neg, Box::new(self.clone())))
    }
}
impl Add for &Value {
    type Output = Value;
    fn add(self, rhs: Self) -> Self::Output {
        let c1 = self.clone().into();
        let c2 = rhs.clone().into();
        Value::Poly(Polynomial::new(vec![c1, c2]))
    }
}
impl Sub for &Value {
    type Output = Value;
    fn sub(self, rhs: Self) -> Self::Output {
        let c1 = self.clone().into();
        let c2 = if let Value::Signed(signed) = rhs {
            signed.clone().into()
        } else {
            PolyChild::new(Sign::Neg, rhs.clone())
        };
        Value::Poly(Polynomial::new(vec![c1, c2]))
    }
}
impl Value {
    pub fn get(&self, pointer: &[usize]) -> Option<&Value> {
        if pointer.len() == 0 {
            Some(self)
        } else {
            match self {
                Value::Mono(mono) => mono[pointer[0]].get(&pointer[1..]),
                Value::Poly(poly) => poly[pointer[0]].inner.get(&pointer[1..]),
                Value::Signed(signed) => if pointer[0] == 0 {
                   signed.inner.get(&pointer[1..])
                } else {
                    None
                },
                _ => None
            }
        }
    }
    pub fn get_mut(&mut self, pointer: &[usize]) -> Option<&mut Value> {
        if pointer.len() == 0 {
            Some(self)
        } else {
            match self {
                Value::Mono(mono) => mono[pointer[0]].get_mut(&pointer[1..]),
                Value::Poly(poly) => poly[pointer[0]].inner.get_mut(&pointer[1..]),
                Value::Signed(signed) => if pointer[0] == 0 {
                   signed.inner.get_mut(&pointer[1..])
                } else {
                    None
                },
                _ => None
            }
        }
    }
    /// a(-ab) -> -aab
    pub fn simplify_brackets(&self) -> Value {
        match self {
            Value::Mono(monomial) => monomial.simplify_brackets(),
            Value::Signed(signed) => signed.simplify_brackets(),
            Value::Poly(polynomial) => polynomial.simplify_brackets(),
            _ => self.clone()
        }
    }
    /// a + a -> 2a
    pub fn unite_similar_mut(&mut self) {
        if let Value::Poly(poly) = self {
            
        }
    }
    /// a + 3a -> 4a
    fn add_combine_mut(&mut self, rhs: &Value) -> Result<(), ()> {
        if let Value::Var(var) = self {
            *self = var.add_combine(rhs)?;
            Ok(())
        } else if let Value::Mono(mono) = self {
            *self = mono.add_combine(rhs)?;
            Ok(())
        } else {
            Err(())
        }
    }
    /// judge whether two values can be the same, even the child in monomial and polynomil are not the same order.
    fn same_after_moving(&self, rhs: &Value) -> bool {
        if let Value::Var(v1) = self {
            if let Value::Var(v2) = rhs {
                v1 == v2
            } else { false }
        } else if let Value::Num(n1) = self {
            if let Value::Num(n2) = rhs {
                n1 == n2
            } else { false }
        } else if let Value::Mono(m1) = self {
            if let Value::Mono(m2) = rhs {
                m1.same_after_moving(m2)
            } else { false }
        } else if let Value::Poly(p1) = self {
            if let Value::Poly(p2) = rhs {
                p1.same_after_moving(p2)
            } else { false }
        } else if let Value::Signed(s1) = self {
            if let Value::Signed(s2) = rhs {
                s1.sign == s2.sign && s1.inner.same_after_moving(&s2.inner)
            } else { false }
        } else { false }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Variable {
    pub main: char,
    pub subscription: Option<String>
}

impl Variable {
    pub fn new(main: char, subscription: Option<String>) -> Self {
        Self { main, subscription }
    }
    fn add_combine(&self, rhs: &Value) -> Result<Value, ()> {
        if let Value::Var(var) = rhs {
            if self == var {
                let coef = Value::Num(2);
                let mono = Monomial::new(vec![coef, Value::Var(self.clone())]);
                return Ok(Value::Mono(mono))
            }
        } else if let Value::Mono(mono) = rhs {
            // handbook standard 1
            if mono.len() != 2 {
                return Err(());
            }
            if let Value::Num(num) = mono[0] {
                if let Value::Var(var) = &mono[1] {
                    if var != self {
                        return Err(());
                    }
                    let new_mono = Monomial::new(vec![Value::Num(num + 1), Value::Var(self.clone())]);
                    return Ok(Value::Mono(new_mono))
                }
            } else if let Value::Signed(ref signed) = mono[0] {
                if let Value::Num(num) = *signed.inner {
                    
                }
            }
        }
        Err(())
    }
}

#[derive(Debug, Clone)]
pub struct Monomial {
    pub children: Vec<Value>,
}

impl Monomial {
    pub fn new(children: Vec<Value>) -> Self {
        Self { children }
    }
    fn add_combine(&self, rhs: &Value) -> Result<Value, ()> {
        let mut self_clone = self.clone();
        if let Value::Var(var2) = rhs {
            // handbook standard 1
            if self_clone.len() != 2 {
                return Err(());
            }
            let second_match = if let Value::Var(ref var1) = self_clone[1] {
                var1 == var2
            } else {
                false
            };
            if !second_match {
                return Err(());
            }
            if let Value::Num(ref mut num) = self_clone[0] {
                *num += 1;
                return Ok(Value::Mono(self_clone));
            }
        } else if let Value::Mono(mono) = rhs {
            let mut test_self = self.clone();
            let mut test_rhs = mono.clone();
            if let Value::Num(c1) = test_self[0] {
                test_self.swap_remove(0);
                if let Value::Num(c2) = test_rhs[0] {
                    test_rhs.swap_remove(0);
                    if test_self.same_after_moving(&test_rhs) {
                        if c1 + c2 == 0 {
                            return Ok(Value::Num(0));
                        } else {
                            self_clone[0] = Value::Num(c1 + c2);
                            return Ok(Value::Mono(self_clone));
                        }
                    }
                } else {
                    if test_self.same_after_moving(&test_rhs) {
                        if c1 + 1 == 0 {
                            return Ok(Value::Num(0));
                        } else {
                            self_clone[0] = Value::Num(c1 + 1);
                            return Ok(Value::Mono(self_clone));
                        }
                    }
                }
            } else {
                if let Value::Num(c2) = test_rhs[0] {
                    test_rhs.swap_remove(0);
                    if test_self.same_after_moving(&test_rhs) {
                        if 1 + c2 == 0 {
                            return Ok(Value::Num(0));
                        } else {
                            self_clone[0] = Value::Num(1 + c2);
                            return Ok(Value::Mono(self_clone));
                        }
                    }
                }
            }
        }
        Err(())
    }
    /// [IMPROVE] this process may contain too many unnecessary clones, change it to mutate itself may improve performance
    fn simplify_brackets(&self) -> Value {
        if self.len() == 1 {
            return self[0].simplify_brackets();
        }
        let mut mono = self.clone();
        let mut possible_sign: Option<Signed> = None;
        for child in mono.iter_mut() {
            *child = child.simplify_brackets();
        };
        let mut i = 0;
        while i < mono.len() {
            if let Value::Mono(ref child_mono) = mono[i] {
                let clone_mono = child_mono.clone();
                let len = clone_mono.len();
                mono.splice(i..=i, clone_mono.children);
                i += len;
            } else if let Value::Signed(ref signed) = mono[i] {
                if signed.sign == Sign::Pos {
                    let new_child = signed.inner.clone();
                    if let Value::Mono(child_mono) = *new_child {
                        let len = child_mono.len();
                        mono.splice(i..=i, child_mono.children);
                        i += len;
                    } else {
                        mono[i] = *new_child;
                        i += 1;
                    }
                } else {
                    mono[i] = *signed.inner.clone();
                    possible_sign = Some(Signed::new(Sign::Neg, Box::new(Value::Mono(mono.clone()))));
                    break;
                }
            } else {
                i += 1;
            }
        }
        if let Some(signed) = possible_sign {
            signed.simplify_brackets()
        } else {
            Value::Mono(mono)
        }
    }
    pub fn move_within(&mut self, from: usize, to: usize) {
        move_within_slice(&mut self.children, from, to);
    }
    /// Currently using sequence search, may be optimized by sorting first than using binary search
    fn same_after_moving(&self, rhs: &Monomial) -> bool {
        let mut self_clone = self.clone();
        let mut rhs_clone = rhs.clone();
        let mut i = 0;
        while i < self_clone.len() && self_clone.len() != 0 {
            let ith = &self_clone[i];
            let found = rhs_clone.iter().position(|v| v.same_after_moving(ith));
            if let Some(found) = found {
                self_clone.swap_remove(i);
                rhs_clone.swap_remove(found);
            } else {
                i += 1;
            };
        }
        if self_clone.len() == 0 && rhs_clone.len() == 0 {
            true
        } else {
            false
        }
    }
}
impl Deref for Monomial {
    type Target = Vec<Value>;
    fn deref(&self) -> &Self::Target {
        &self.children
    }
}
impl DerefMut for Monomial {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.children
    }
}

impl From<&str> for Variable {
    fn from(value: &str) -> Self {
        let mut seperation = value.split("_");
        let main = seperation.next().unwrap().chars().next().unwrap();
        let subscription = if let Some(s) = seperation.next() {
            Some(s.to_owned())
        } else { None };
        Self { main, subscription }
    }
}

impl From<char> for Variable {
    fn from(value: char) -> Self {
        Self { main: value, subscription: None }
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Sign {
    Pos, Neg
}
impl Neg for Sign {
    type Output = Sign;
    fn neg(self) -> Self::Output {
        match self {
            Sign::Neg => Sign::Pos,
            Sign::Pos => Sign::Neg
        }
    }
}
impl Sign {
    fn conteract(&self, other: Sign) -> Sign {
        if other == *self {
            Sign::Pos
        } else {
            Sign::Neg
        }
    }
}

#[derive(Debug, Clone)]
pub struct Signed {
    pub sign: Sign,
    pub inner: Box<Value>,
}

impl Signed {
    pub fn new(sign: Sign, inner: Box<Value>) -> Self {
        Self { sign, inner }
    }
    fn simplify_brackets(&self) -> Value {
        if self.sign == Sign::Pos {
            return self.inner.simplify_brackets();
        }
        let mut signed = self.clone();
        *signed.inner = signed.inner.simplify_brackets();
        if let Value::Signed(ref inner_signed) = *signed.inner {
            signed.sign = inner_signed.sign.conteract(signed.sign);
            signed.inner = inner_signed.inner.clone();
            Value::Signed(signed)
        } else if let Value::Poly(poly) = *signed.inner {
            Value::Poly(-poly)
        } else {
            Value::Signed(signed)
        }
    }
}

#[derive(Debug, Clone)]
pub struct Polynomial {
    pub children: Vec<PolyChild>,
}
#[derive(Debug, Clone)]
pub struct PolyChild {
    pub sign: Sign,
    pub inner: Value,
}
impl PolyChild {
    pub fn new(sign: Sign, inner: Value) -> Self {
        Self { inner, sign }
    }
}
impl From<Signed> for PolyChild {
    fn from(value: Signed) -> Self {
        Self { inner: *value.inner, sign: value.sign }
    }
}
impl From<Value> for PolyChild {
    fn from(value: Value) -> Self {
        if let Value::Signed(signed) = value {
            signed.into()
        } else {
            Self::new(Sign::Pos, value)
        }
    }
}
impl Neg for &PolyChild {
    type Output = PolyChild;
    fn neg(self) -> Self::Output {
        let mut result = self.clone();
        result.sign = -result.sign;
        result
    }
}
impl Neg for PolyChild {
    type Output = PolyChild;
    fn neg(mut self) -> Self::Output {
        self.sign = -self.sign;
        self
    }
}
impl Deref for Polynomial {
    type Target = Vec<PolyChild>;
    fn deref(&self) -> &Self::Target {
        &self.children
    }
}
impl DerefMut for Polynomial {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.children
    }
}
impl Neg for Polynomial {
    type Output = Polynomial;
    fn neg(mut self) -> Self::Output {
        for child in self.iter_mut() {
            child.sign = -child.sign;
        }
        self
    }
}

impl Polynomial {
    pub fn new(children: Vec<PolyChild>) -> Self {
        Self { children }
    }
    pub fn move_within(&mut self, from: usize, to: usize) {
        move_within_slice(&mut self.children, from, to);
    }
    fn simplify_brackets(&self) -> Value {
        let mut poly = self.clone();
        for child in poly.iter_mut() {
            child.inner = child.inner.simplify_brackets();
        }
        let mut i = 0;
        while i < poly.len() {
            if let Value::Poly(ref child_poly) = poly[i].inner {
                let clone_poly = child_poly.clone();
                let len = clone_poly.len();
                if poly[i].sign == Sign::Neg {
                    poly.splice(i..=i, (-clone_poly).children);
                } else {
                    poly.splice(i..=i, clone_poly.children);
                }
                i += len;
            } else if let Value::Signed(ref signed) = poly[i].inner {
                let inner = *signed.inner.clone();
                poly[i].sign = signed.sign.conteract(poly[i].sign);
                poly[i].inner = inner;
                i += 1;
            } else {
                i += 1;
            }
        }
        Value::Poly(poly)
    }
    fn same_after_moving(&self, rhs: &Polynomial) -> bool {
        let mut self_clone = self.clone();
        let mut rhs_clone = rhs.clone();
        let mut i = 0;
        while i < self_clone.len() && self_clone.len() != 0 {
            let ith = &self_clone[i];
            let found = rhs_clone.iter().position(|c| {
                c.sign == ith.sign && c.inner.same_after_moving(&ith.inner)
            });
            if let Some(found) = found {
                self_clone.swap_remove(i);
                rhs_clone.swap_remove(found);
            } else {
                i += 1;
            }
        }
        if self_clone.len() == 0 && rhs_clone.len() == 0 {
            true
        } else {
            false
        }
    }
}

fn move_within_slice<T>(slice: &mut [T], from: usize, to: usize) {
    if from < to {
        slice[from..to].rotate_left(1);
    } else if from > to {
        slice[to..=from].rotate_right(1)
    }
}